﻿// -----------------------------------------------------------------------
// <copyright file="Serializer.BlockArray{T}.cs" company="none">
// Copyright (c) 2012 M. Alberti, xanatos(at)live.it
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// </copyright>
// -----------------------------------------------------------------------

namespace FluentSerializer
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// 
    /// </summary>
    public abstract partial class Serializer
    {
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class BlockArray<T>
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="array"></param>
            public BlockArray(T[] array)
            {
                if (array == null || array.Length == 0)
                {
                    array = new T[Growth];
                }

                this.CurrentBlock = array;
            }

            /// <summary>
            /// 
            /// </summary>
            public T[] CurrentBlock { get; protected set; }

            /// <summary>
            /// 
            /// </summary>
            public int Index { get; set; }

            /// <summary>
            /// 
            /// </summary>
            protected List<T[]> Blocks { get; set; }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="growth"></param>
            public void AllocateBlock(int growth = Growth)
            {
                if (this.Blocks == null)
                {
                    this.Blocks = new List<T[]>();
                    this.Blocks.Add(this.CurrentBlock);
                }

                var array = new T[growth];
                this.Blocks.Add(array);
                this.CurrentBlock = array;
                this.Index = 0;
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="item"></param>
            public void Add(T item)
            {
                if (this.Index == this.CurrentBlock.Length)
                {
                    this.AllocateBlock();
                }

                this.CurrentBlock[this.Index] = item;
                this.Index++;
            }

            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            public T[] Detach()
            {
                T[] array;

                if (this.Blocks == null)
                {
                    array = this.CurrentBlock;

                    if (array.Length != this.Index)
                    {
                        Array.Resize(ref array, this.Index);
                    }

                    this.CurrentBlock = null;
                    return array;
                }

                array = this.Blocks[0];

                int size = array.Length + ((this.Blocks.Count - 2) * Growth) + this.Index;
                int index = array.Length;
                int count = this.Blocks.Count - 1;
                Array.Resize(ref array, size);

                for (int i = 1; i < count; i++)
                {
                    Array.Copy(this.Blocks[i], 0, array, index, Growth);
                    index += Growth;
                }

                Array.Copy(this.CurrentBlock, 0, array, index, this.Index);

                this.CurrentBlock = null;
                return array;
            }
        }
    }
}